/*
 * inotify-sync - a simple file synchronizer and file system watcher
 * Copyright (C) 2010-2011, inotify-sync developers and inotify-sync contributors
 * Copyright (C) 2010-2011, Cohesion Network Security Studio
 *
 * inotify-sync is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * inotify-sync is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with inotify-sync; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "event_handler.h"

void
event_handler_init()
{
	if(-1 == access(watch_dir, R_OK|X_OK))
	{
		perror("access()");
		exit(errno);
	}

	// 同步目录如果不为空则必须有rwx的权限
	if(strcmp(sync_dir, "") && -1 == access(sync_dir, R_OK|W_OK|X_OK))
	{
		perror("access()");
		exit(errno);
	}

	// 临时目录如果不为空则必须有rwx的权限
	if(strcmp(temp_dir, "") && -1 == access(temp_dir, R_OK|W_OK|X_OK))
	{
		if(-1 == mkdir(temp_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH))
		{
			perror("mkdir()");
			exit(errno);
		}
	}

	if(strcmp(common_action, "") && -1 == access(common_action, R_OK|X_OK))
	{
		perror("access()");
		exit(errno);
	}

	int i;
	for(i = 0; i < sizeof(event_action_array)/sizeof(struct event_action); i++)
	{
		if(strcmp(event_action_array[i].action, "")
		&& -1 == access(event_action_array[i].action, R_OK|X_OK))
		{
			perror("access()");
			exit(errno);
		}
	}
	
	if(-1 == access(custom_log, R_OK|W_OK))
	{
		perror("access()");
		exit(errno);
	}

	if(-1 == access(error_log, R_OK|W_OK))
	{
		perror("access()");
		exit(errno);
	}
}

void
event_handler_destory()
{}

void
event_handler_handle
(
	char **wd_path_map,
	const struct ievent_queue * const ievent_queue_p
)
{
	struct ievent_queue *iq_node_p = (struct ievent_queue *)ievent_queue_p;
	while(iq_node_p != NULL)
	{
		// 事件指针
		struct inotify_event *p_ievent = NULL;
		// 事件发生目录
		char *p_fpath = NULL;
		// 事件发生相对路径
		char *p_frpath = NULL;
		// 事件掩码
		uint32_t mask;
		// 事件cookie
		char cookie[12];


		// 取出当前事件指针
		p_ievent = iq_node_p->event;
		// 根据当前事件wd获得事件发生目录
		p_fpath = (char *)malloc(strlen(wd_path_map[p_ievent->wd])+1);
		strcpy(p_fpath, wd_path_map[p_ievent->wd]);
		p_frpath = NULL;
		// 事件掩码
		mask = p_ievent->mask;
		// 获得事件cookie
		sprintf(cookie, "%d", p_ievent->cookie);



		// 如不为IN_DELETE_SELF或IN_MOVE_SELF事件，则绝对路径
		// 为：事件发生目录 + 文件名
		if(!(mask & IN_DELETE_SELF)
		&& !(mask & IN_MOVE_SELF))
		{
			p_fpath = (char *)realloc(p_fpath,
				strlen(p_fpath) + 1 + strlen(p_ievent->name) + 1);
			strcat(p_fpath, "/");
			strcat(p_fpath, p_ievent->name);
		}
		// 文件相对于监控根目录的路径
		p_frpath = p_fpath + strlen(watch_dir);

		// 对创建目录事件，初始化监控目录
		if((mask & IN_CREATE) && (mask & IN_ISDIR))
		{
			init_dir(p_fpath);
		}
		// 对删除目录事件，撤销监控目录
		if((mask & IN_DELETE) && (mask & IN_ISDIR))
		{
			destory_dir(p_fpath);
		}
		// 对移入目录事件，初始化监控目录
		if((mask & IN_MOVED_TO) && (mask & IN_ISDIR))
		{
			init_dir(p_fpath);
		}
		// 对移出目录事件，初始化监控目录
		if((mask & IN_MOVED_FROM) && (mask & IN_ISDIR))
		{
			destory_dir(p_fpath);
		}

		int i;
		for(i = 0; i < sizeof(event_action_array)/sizeof(struct event_action); i++)
		{
			if(mask & event_action_array[i].event)
			{
				exec_action(event_action_array[i].action,
						p_frpath,
						p_fpath,
						ISDIR(mask),
						cookie);
			}
		}
		free(p_fpath);
		iq_node_p = iq_node_p->next; 
	}
}

inline void
exec_action
(
	const char *action,
	const char *p_frpath,
	const char *p_fpath,
	const char *is_dir,
	const char *cookie
)
{
	// 新开一个进程运行对应的action脚本
	pid_t pid;
	if((pid = fork()) < 0)
	{
		perror("fork()");
	}
	else if(pid == 0)
	{
		execl
		(
			action,
			"",
			common_action,
			watch_dir,
			p_frpath,
			p_fpath,
			is_dir,
			sync_dir,
			cookie,
			temp_dir,
			custom_log,
			error_log,
			log_enable,
			(char *)0
		);
	}
	if(waitpid(pid,NULL,0) < 0)
	{
		perror("waitpid()");
	}
}
